// 1.3.2 指针-其他概念-指针的算术运算

/**
 * 
 * 学习 C++ 的指针既简单又有趣。通过指针，可以简化一些 C++ 编程任务的执行，还有一些任务，如动态内存分配，没有指针是无法执行的。所以，想要成为一名优秀的 C++ 程序员，学习指针是很有必要的。
 * 正如您所知道的，每一个变量都有一个内存位置，每一个内存位置都定义了可使用连字号（&）运算符访问的地址，它表示了在内存中的一个地址。请看下面的实例，它将输出定义的变量地址：
 * 
 * ------------------
 * 其他概念
 * 在 C++ 中，有很多指针相关的概念，这些概念都很简单，但是都很重要。下面列出了 C++ 程序员必须清楚的一些与指针相关的重要概念：
 * 
 * 1. C++ Null 指针
 * C++ 支持空指针。NULL 指针是一个定义在标准库中的值为零的常量。
 * 
 * 2. C++ 指针的算术运算
 * 可以对指针进行四种算术运算：++、--、+、-
 * 
 * 3. C++ 指针 vs 数组
 * 指针和数组之间有着密切的关系。
 * 
 * 4. C++ 指针数组
 * 可以定义用来存储指针的数组。
 * 
 * 5. C++ 指向指针的指针
 * C++ 允许指向指针的指针。
 * 
 * 6. C++ 传递指针给函数
 * 通过引用或地址传递参数，使传递的参数在调用函数中被改变。
 * 
 * 7. C++ 从函数返回指针
 * C++ 允许函数返回指针到局部变量、静态变量和动态内存分配。
 * 
 * ~~~~~~~~~~~~~~~~~~~~
 * 指针的算术运算
 * 指针是一个用数值表示的地址。因此，您可以对指针执行算术运算。可以对指针进行四种算术运算：++、--、+、-。
 * 
 * 假设 ptr 是一个指向地址 1000 的整型指针，是一个 32 位的整数，让我们对该指针执行下列的算术运算

    ptr++;

 * 在执行完上述的运算之后，ptr 将指向位置 1004，因为 ptr 每增加一次，它都将指向下一个整数位置，即当前位置往后移 4 个字节。这个运算会在不影响内存位置中实际值的情况下，移动指针到下一个内存位置。如果 ptr 指向一个地址为 1000 的字符，上面的运算会导致指针指向位置 1001，因为下一个字符位置是在 1001。
 *
 * 递增一个指针
 * 我们喜欢在程序中使用指针代替数组，因为变量指针可以递增，而数组不能递增，因为数组是一个常量指针。下面的程序递增变量指针，以便顺序访问数组中的每一个元素：
 *
 * 递减一个指针
 * 同样地，对指针进行递减运算，即把值减去其数据类型的字节数，如下所示：
 * 
 * 指针的比较
 * 指针可以用关系运算符进行比较，如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量，比如同一个数组中的不同元素，则可对 p1 和 p2 进行大小比较。
 * 下面的程序修改了上面的实例，只要变量指针所指向的地址小于或等于数组的最后一个元素的地址 &var[MAX - 1]，则把变量指针进行递增：
*/

#include <iostream>

int main(void)
{
  int a = 100;
  int b = 200;
  int *ptr = &a;

  std::cout << "ptr: " << ptr << std::endl; // 0x61fe0c
  ptr++;
  std::cout << "ptr: " << ptr << std::endl; // 0x61fe10
  std::cout << "*ptr: " << *ptr << std::endl;

  /**
   * 递增一个指针
   * 
  */
  const int size = 3;
  int arr[size] = {5, 7, 9};
  ptr = arr;
  for (int i = 0; i < size; i++)
  {
    // std::cout << "arr[" << i << "] = " << *(arr + i) << std::endl;
    std::cout << "arr[" << i << "] = " << *ptr << std::endl;
    ptr++;
  }

  /**
   * 递减一个指针
   * 
  */
  ptr = &arr[size - 1];
  for (int i = size - 1; i >= 0; i--)
  {
    std::cout << "arr[" << i << "] = " << *ptr << std::endl;
    ptr--;
  }

  /**
   * 指针的比较
   * 
  */
  int num1 = 10;
  int *ptr1 = &num1;

  double d1 = 1.00;
  double *ptr2 = &d1;
  std::cout << "ptr1: " << ptr1 << std::endl;        // 0x61fde4
  std::cout << "ptr2: " << ptr2 << std::endl;        // 0x61fdd8
  std::cout << "ptr2: " << (int *)ptr2 << std::endl; // 0x61fdd8
  // comparison between distinct pointer types 'int*' and 'double*' lacks a cast [-fpermissive]
  if (ptr1 > (int *)ptr2)
  {
    std::cout << "ptr1 > ptr2" << std::endl;
  }
  else if (ptr1 < (int *)ptr2)
  {
    std::cout << "ptr1 < ptr2" << std::endl;
  }
  // ptr = arr;

  ptr = arr;
  int i = 0;
  while (ptr <= &arr[size - 1])
  {
    std::cout << "arr[" << i << "] = " << *ptr << std::endl;
    i++;
    ptr++;
  }

  int test[3] = {1, 2, 3};
  std::cout << "&test : " << &test << std::endl;       // 0x61fdc4
  std::cout << "&test[0] : " << &test[0] << std::endl; // 0x61fdc4
  std::cout << "test : " << test << std::endl;         // 0x61fdc4

  // int *p = &test;// error: cannot convert 'int (*)[3]' to 'int*' in initialization

  // int *p;
  // p = &test;// error: cannot convert 'int (*)[3]' to 'int*' in assignment



  printf("-------------end--------------\n");
  return 0;
}